<template>
	<view class="choose-time">
		<view class="choose-time-content flex-spb-cn" @click="onShowPicker">
			<template v-if="!value">
				<slot name="placeholder" v-if="$slots['placeholder']"></slot>
				<text v-else class="time-pl word-keep">{{placeholder}}</text>
			</template>
			<template v-else>
				<slot v-if="$slots['default']"></slot>
				<view class="choose-label text-ellipsis">{{value}}</view>
			</template>
			<text class="qh-rt-single qh-rt-you right-icon"></text>
		</view>
		<qh-popup v-if="showPicker" v-model="showPicker" :title="title" @cancel="cancel" @confirm="confirm" :cancelText="clearable?'清空':'取消'"
			contentStyle="padding:0">
			<view class="picker-view-box">
				<picker-view indicator-style="{height: 50px}" indicator-class="picker-view-indicator-class" class="picker-view" :value="multiIndex"
					@change="pickerChange">
					<picker-view-column v-for="(column, index) in multiArray" :key="index">
						<view class="picker-view-item" v-for="(item, i) in column" :key="i">{{item}}</view>
					</picker-view-column>
				</picker-view>
			</view>
		</qh-popup>
	</view>
</template>

<script>
	import toDecimal from '@/utils/toDecimal.js';
	const app = getApp().globalData;

	/**
	 * 下单选择时间的组件，此组件不支持动态绑定
	 */
	export default {
		name: "choose-time",
		props: {
			value: {
				type: String,
				default: '',
			},
			timeRange: {
				type: Array,
				default () {
					return [
						['00:00', '23:59']
					]
				}
			}, //可选时间范围
			delayTime: {
				type: [Number, String],
				default: 0,
			}, //延迟时间 单位：分
			autoSetTime: {
				type: Boolean,
				default: false,
			}, //是否自动选择最近的时间
			title: {
				type: String,
				default: '选择时间',
			}, //弹框标题
			placeholder: {
				type: String,
				default: '选择时间'
			}, //占位符
			fontSize: {
				type: [String, Number],
				default: ''
			}, //字体大小，优先使用每个style里的字体大小
		},
		emits: ['update:value', 'change', 'input'],
		data() {
			return {
				showPicker: false,
				multiArray: [
					[],
					[],
					[]
				],
				multiIndex: [0, 0, 0],
				defaultIndex: [0, 0, 0],
				chooseData: [],
				caculTime: [],
				timeArrEsDay: 0,
			};
		},
		methods: {
			//打开弹窗
			onShowPicker() {
				this.showPicker = true;
			},
			//取消
			cancel(type) {
				this.showPicker = false;
			},
			//确认选择时间
			confirm(e) {
				let monthDay = this.multiArray[0][this.multiIndex[0]];
				let hours = this.multiArray[1][this.multiIndex[1]];
				let minute = this.multiArray[2][this.multiIndex[2]];
				if (monthDay === "今天") {
					let month = new Date().getMonth() + 1;
					let day = new Date().getDate();
					monthDay = month + "月" + day + "日";
				} else if (monthDay === "明天") {
					let date1 = new Date();
					date1.setDate(new Date().getDate() + 1);
					monthDay = date1.getMonth() + 1 + "月" + date1.getDate() + "日";
				} else {
					let month = monthDay.split("-")[0]; // 返回月

					let day = monthDay.split("-")[1]; // 返回日

					monthDay = month + "月" + day + "日";
				}

				let startDate = monthDay + " " + hours + ":" + minute;

				this.$emit('input', startDate);

				this.showPicker = false;
			},
			//生成可选月日
			async loadMonthDate() {
				const data = await this.createMonthDay(this.caculTime, this.delayTime * 60);
				this.$set(this.multiArray, 0, data);
				this.$forceUpdate()
			},
			//生成可选时
			async loadHours() {
				const data = await this.createHours(this.caculTime, this.multiArray, this.multiIndex, this.delayTime * 60);
				this.$set(this.multiArray, 1, data);
				this.$forceUpdate()
			},
			//生成可选分
			async loadMinutes() {
				const data = await this.createMinutes(this.caculTime, this.multiArray, this.multiIndex, this.delayTime * 60);
				this.$set(this.multiArray, 2, data);
				this.$forceUpdate()
			},
			/**
			 * 配送、自提时间选择生成 月-日 数组
			 * @param times 固定的时间段数组[[[10,00],[12,00]],[[12,30],[14,50]],[[17,00],[20,30]]]
			 * @param es_time 需要往后延长的开始时间的长度(秒为单位)
			 * @param end_day 结束的天数 默认7天月日
			 * @return Array 返回一个 月-日 的数组
			 */
			createMonthDay(times, es_time = 0, end_day = 0) {
				return new Promise(resolve => {
					let timeData = this.getThisTime(times);
					let monthDay = []; //月日列表
					let thisTime = timeData.thisTime; //当前时间的时间戳精确到秒
					//临时计算往后延长到的时间的时间戳
					let temp_time = toDecimal(thisTime + es_time * 1000 - timeData.startTime, 0);
					let day = parseInt(toDecimal(temp_time / 86400000)); //计算需要往后延长的天

					this.timeArrEsDay = day; //存储实际延时的天数
					let this_day_more = temp_time % 86400; //减掉天之后剩余的时间戳
					if (day < 1) {
						if (thisTime + es_time * 1000 > timeData.endTime) {
							monthDay = ['明天'];
							thisTime = thisTime + 172800000;
							day = 1;
						} else {
							monthDay = ['今天', '明天'];
							thisTime = thisTime + 172800000;
							day = 2;
						}
					} else if (day == 1 && thisTime + es_time * 1000 < timeData.endTime) {
						monthDay = ['明天'];
						thisTime = thisTime + 172800000;
					} else {
						thisTime += es_time * 1000;
						//计算是延迟后最晚的时间是多少秒
						let end = parseInt(toDecimal(timeData.startTime + day * 86400000 + times[times.length - 1][1][0] * 3600000 + times[times.length -
							1][1][1] * 60000));
						if (thisTime > end) {
							//不足够再加一天
							thisTime += 86400000;
							day += 1;
						}
						//把明天转为文字的明天
						if (thisTime - timeData.startTime < 86400000 * 2) {
							monthDay = ['明天'];
							thisTime += 86400000;
						}
						this.timeArrEsDay = day; //存储实际延时的天数
					}
					if (end_day == 0) end_day = toDecimal(day + 7 - monthDay.length);
					for (let i = day; i <= end_day; i++) {
						let md = app.getDate('m-d', thisTime);
						thisTime += 86400000;
						monthDay.push(md);
					}
					resolve(monthDay)
				})
			},
			/**
			 * 配送、自提时间选择生成 时 数组
			 * @param times 固定的时间段数组[[[10,00],[12,00]],[[12,30],[14,50]],[[17,00],[20,30]]]
			 * @param cd 已生成的 月日,时,分 的数组
			 * @param ci 已选的 月日,时,分 下标的数组
			 * @param es_time 需要往后延长的开始时间的长度(秒为单位)
			 * @return Array 返回一个 时 的数组
			 */
			createHours(times, cd, ci, es_time = 0) {
				return new Promise(resolve => {
					let hours = [];
					let timeData = this.getThisTime(times);
					let thisTime = timeData.thisTime; //当前时间的时间戳精确到秒
					//临时计算往后延长到的时间的时间戳
					let temp_time = toDecimal(thisTime + es_time * 1000 - timeData.startTime);
					let day = parseInt(toDecimal(temp_time / 86400000)); //计算需要往后延长的天
					//针对不足加一的情况
					if (day == 0 && ci[0] == 0 && cd[0][0] == '明天') {
						temp_time = 0;
					} else if (day < this.timeArrEsDay) {
						temp_time = 0;
					}
					let h = parseInt((temp_time % 86400000) / 3600000); //计算需要往后延长的时
					let m = parseInt((temp_time % 3600000) / 60000); //计算需要往后延长的分

					times.forEach((item) => {
						let i = item[0][0] * 1;
						let len = item[1][0] * 1;
						//时小于10前面补0
						//时的数组跑循环，从今天的起始时到结束时
						for (i; i <= len; i++) {
							// console.log('进入循环')
							let hh = i >= 10 ? i : ('0' + i);
							if (ci[0] != 0) {
								// console.log(i+': 选择的日不是第一项，插入时');
								//选择的日不是第一项，插入时
								(hours.indexOf(hh) == -1) && hours.push(hh);
							} else {
								//选择的日是第一项
								//判断循环到的时是否大于延时的时并且循环到的时
								if (i > h) {
									// console.log(i+': 循环到的时大于延时的时，插入时');
									//循环到的时大于延时的时，插入时
									(hours.indexOf(hh) == -1) && hours.push(hh);
								} else if (i == h && i != len) {
									// console.log(i+': 循环到的时等于延时的时并且不是可选时间的最后一个时，插入时');
									//循环到的时等于延时的时并且不是可选时间的最后一个时，插入时
									(hours.indexOf(hh) == -1) && hours.push(hh);
								} else if (i == h && i == len && m < item[1][1] * 1) {
									// console.log(i+': 循环到的时等于延时的时并且是可选时间的最后一个时并且延时的分是否小于可选分，插入时');
									//循环到的时等于延时的时并且是可选时间的最后一个时并且延时的分是否小于可选分，插入时
									(hours.indexOf(hh) == -1) && hours.push(hh);
								}
							}
						}
					});
					resolve(hours);
				})
			},
			/**
			 * 配送、自提时间选择生成 分 数组
			 * @param times 固定的时间段数组[[[10,00],[12,00]],[[12,30],[14,50]],[[17,00],[20,30]]]
			 * @param cd 已生成的 月日,时,分 的数组
			 * @param ci 已选的 月日,时,分 下标的数组
			 * @param es_time 需要往后延长的开始时间的长度(秒为单位)
			 * @return Array 返回一个 分 的数组 基本间隔为5分钟
			 */
			createMinutes(times, cd, ci, es_time = 0) {
				return new Promise(resolve => {
					let minutes = [];
					let timeData = this.getThisTime(times);
					let thisTime = timeData.thisTime; //当前时间的时间戳精确到秒
					//临时计算往后延长到的时间的时间戳
					let temp_time = toDecimal(thisTime + es_time * 1000 - timeData.startTime);
					let h = parseInt((temp_time % 86400000) / 3600000); //计算需要往后延长的时
					let m = parseInt((temp_time % 3600000) / 60000); //计算需要往后延长的分
					times.forEach((item) => {
						if (cd[1][ci[1]] * 1 >= item[0][0] * 1 && cd[1][ci[1]] * 1 <= item[1][0] * 1) {
							let start = 0;
							let end = 59;
							if (cd[1][ci[1]] * 1 == item[0][0] * 1) {
								//选择的时等于开始时 start定为开始的秒
								start = item[0][1];
							}
							if (cd[1][ci[1]] * 1 == item[1][0] * 1) {
								//选择的时等于结束时 end定为结束的秒
								end = item[1][1];
							}
							// console.log(start,end,m)
							if (ci[0] == 0 && ci[1] == 0 && cd[1][0] * 1 == h && es_time > 0 && m >= start) {
								//选择第一项月日和第一项时 且第一项的时等于当前时间 start定为延时的秒
								// console.log(123456);
								start = m;
							} else if (ci[0] == 0 && ci[1] == 0 && h >= item[0][0] * 1 && cd[0][0] == '今天' && m >
								start) {
								//选择第一项是今天 并且时是当前时，判断分的其起始值
								// console.log(456789);
								start = m;
							}
							// console.log(start,end,m,h,timeData.thisHours)
							//如果开始时间小于等于结束时间则写入秒的数组
							if (start <= end) {
								start = start * 1; //转为数字
								end = end * 1; //转为数字
								let multiple = (start * 1) % 5; //获取余数
								if (multiple > 0) {
									minutes.push(start >= 10 ? start : ('0' + start));
									start = toDecimal(start + (5 - multiple));
								}
								if (start >= 60) return false;
								for (let i = start; i <= end; i += 5) {
									minutes.push(i >= 10 ? i : ('0' + i));
								}
							}
							return false;
						}
					});
					resolve(minutes);
				})
			},
			/**
			 * 获取当前时间等信息
			 * @param times 固定的时间段数组[[[10,00],[12,00]],[[12,30],[14,50]],[[17,00],[20,30]]]
			 */
			getThisTime(times) {
				let date = new Date();
				let thisYears = date.getFullYear(); //当前年
				let thisMonth = date.getMonth() + 1; //当前月
				let thisDate = date.getDate(); //当前日
				let thisHours = date.getHours(); //当前时
				let thisMinutes = date.getMinutes(); //当前分
				let len = times.length - 1;
				let start_time = thisYears + '/' + thisMonth + '/' + thisDate + ' 00:00:00'; //当天的开始时间
				let end_time = thisYears + '/' + thisMonth + '/' + thisDate + ' ' + times[len][1][0] + ':' + times[len][1][1] + ':00'; //当天的结束时间

				return {
					thisYears: thisYears, //当前年
					thisMonth: thisMonth, //当前月
					thisDate: thisDate, //当前日
					thisHours: thisHours, //当前时
					thisMinutes: thisMinutes, //当前分
					thisTime: Date.parse(new Date()), //当前时间戳
					startTime: Date.parse(new Date(start_time)), //今日开始时间戳
					endTime: Date.parse(new Date(end_time)) //今日结束时间戳
				};
			},
			// 重置选择的时间
			async selectTime(bool) {
				await this.loadMonthDate(); //生成可选月日
				await this.loadHours(); //生成可选时
				await this.loadMinutes(); //生成可选分

				//自动选择时间
				bool && this.$nextTick(() => {
					this.confirm({
						detail: {
							value: [0, 0, 0]
						}
					})
				})
			},
			//滚动选项
			pickerChange(e) {
				if (e.detail.value[0] !== this.multiIndex[0]) {
					//日期列改变
					this.multiIndex[0] = e.detail.value[0];
					this.multiIndex[1] = 0;
					this.multiIndex[2] = 0;
					this.$nextTick(async () => {
						await this.loadHours();
						await this.loadMinutes();
					})
				} else if (e.detail.value[1] !== this.multiIndex[1]) {
					// 如果是第2列 小时改变
					this.multiIndex[0] = e.detail.value[0];
					this.multiIndex[1] = e.detail.value[1];
					this.multiIndex[2] = 0;
					this.$nextTick(async () => {
						await this.loadMinutes();
					})
				} else {
					this.multiIndex = e.detail.value;
				}
			},
			//处理营业时间、发货时间为二维数组
			handleTimeArr(times) {
				let arr = [];
				times.forEach((item) => {
					arr.push([item[0].split(':'), item[1].split(':')]);
				});
				return arr;
			},
		},
		async created() {
			await this.$onLaunched;
			this.caculTime = this.handleTimeArr(this.timeRange);
			this.selectTime(this.autoSetTime ? true : false);
		},
	}
</script>

<style lang="scss">
	.choose-time {
		background: transparent;
		line-height: 32rpx;
		max-width: 100%;

		.choose-time-content {
			max-width: 100%;
		}

		.time-pl {
			color: var(--primary-color);
			font-size: 30rpx;
			line-height: 42rpx;
		}

		.choose-label {
			font-size: 30rpx;
			color: var(--primary-color);
		}

		.picker-view-box {
			width: 100%;
			box-sizing: border-box;
			padding: 0 36rpx;

			.picker-view {
				width: 100%;
				height: 750rpx;
			}

			.picker-view-indicator-class {
				/* #ifdef MP-WEIXIN */
				height: 50px;
				/* #endif */
			}

			.picker-view-item {
				/* #ifdef MP-WEIXIN */
				height: 50px;
				font-size: 30rpx;
				line-height: 50px;
				/* #endif */
				align-items: center;
				justify-content: center;
				text-align: center;
				color: #1E1E1E;
			}
		}

		.right-icon {
			font-size: 18rpx;
			color: #929397;
			margin-left: 10rpx;
		}
	}
</style>
